/**************************************************************************
 //* W Corp. 
 //* W Profile Services                                             
 //* Package:  by.doubleyou.monitor.peer
 //* (C) Copyright W Corp.  2007
 /**************************************************************************
 *
 * Copyright (c) 2007, W Corporation
 * All rights reserved.
 * 
 * Version: 1.0
 * Date:  3 Dec, 2007, Author: Alexander J. Perez Tchernov
 * 
 * MODIFICATION HISTORY:
 * Defect/Feature  	Description
 * ---
 */
package by.doubleyou.monitor.peer;

import java.net.HttpURLConnection;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import by.doubleyou.core.config.PeerConfig;
import by.doubleyou.core.gms.GMSClientService;

import com.sun.enterprise.ee.cms.core.GMSException;
import com.sun.grizzly.http.SelectorThread;
import com.sun.grizzly.tcp.ActionCode;
import com.sun.grizzly.tcp.Adapter;
import com.sun.grizzly.tcp.OutputBuffer;
import com.sun.grizzly.tcp.Request;
import com.sun.grizzly.tcp.Response;
import com.sun.grizzly.util.buf.ByteChunk;

/**
 * Basic class to count the number of visitors. Used as individual peer in
 * cluster.
 * 
 * @author Alexander J. Perez Tchernov
 * @author James Lorenzen
 * 
 */
public class AgregatorService extends GMSClientService implements Adapter {

	/**
	 * pattern to extract reference from http://host/visit/{ref}
	 */
	// TODO check to use dk.brics.automaton instead
	final static Pattern p = Pattern.compile("^/visit/(\\d+)");// 

	/**
	 * Grizzly NIO thread
	 */
	private SelectorThread st;

	// TODO X-DOCLET
	// TODO version from property
	private static final String INFO = "W-Monitoring v. 0.3: request is succesfully processed  by {0} on {1} server-instance";

	// private static ByteChunk chunk = new ByteChunk();

	private static PeerConfig config;
	static {

		try {
			// chunk.append(INFO.getBytes(), 0, INFO.getBytes().length);
			config = PeerConfig.getInstance();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}

	}

	/**
	 * Construct to initialize Agregator with no GMS support
	 * 
	 */
	public AgregatorService() {
		super("w-agregator", "standalone", true);
	}

	// ------------------------- GMS -----------------------------
	/**
	 * Constructor to initilize GMSService
	 * 
	 * @param serviceName
	 * @param memberToken
	 * @param sendMessages
	 */
	public AgregatorService(final String serviceName, final String memberToken,
			final boolean sendMessages) {
		super(serviceName, memberToken, sendMessages);
	}

	@Override
	public void run() {
		super.run();
		st = new SelectorThread();
		// TODO load the bunch of options from
		// http://weblogs.java.net/blog/jfarcand/archive/2007/10/22_unpublished.html
		//
		int port = config.getPort();
		st.setPort(port);
		st.setAdapter(this);
		try {
			st.initEndpoint();
			st.startEndpoint();
		} catch (Exception e) {
			// TODO logging
			System.out.println("Exception in SelectorThread: " + e);
		} finally {
			stopClient();
		}

	}

	@Override
	public void stopClient() {
		if (st.isRunning()) {
			st.stopEndpoint();
		}
		super.stopClient();
	}

	// ------------------------- / GMS -----------------------------

	// ------------------------- Grizzly -----------------------------

	/**
	 * Grizzly handle()
	 * 
	 * @see Grizzly Adapter
	 */
	public void service(Request request, Response response) throws Exception {
		String requestURI = request.requestURI().toString();

		// grizzly tends to minimize all actions, so we need to switch on ip
		// logging
		request.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, null);

		// match the uri
		// TODO check to use dk.brics.automaton instead
		Matcher matcher = p.matcher(requestURI);
		if (matcher.find()) {
			getLogger().log(
					Level.INFO,
					"{ id = " + matcher.group(1) + ", ip = "
							+ request.remoteAddr() + " }");

			// TODO direct nio transfer + splitting
			// TODO grizzly
			try {
				getGMS().getGroupHandle().sendMessage(
						"w-storage",
						/* FORMAT: ip time id */
						MessageFormat.format("{0} {1} {2}",
								request.remoteAddr(), request.getStartTime(),
								matcher.group(1)).getBytes());

			} catch (GMSException e) {
				getLogger().log(Level.INFO, e.getMessage());
			}

		}

		// send response
		if (request.method().toString().equalsIgnoreCase("GET")) {
			response.setStatus(HttpURLConnection.HTTP_OK);

			String responceText = MessageFormat.format(INFO, getServiceName(),
					getMemberToken());
			System.out.println(responceText);
			response.setContentLength(responceText.getBytes().length);
			response.setContentType("text/plain");

			ByteChunk chunkInstance = new ByteChunk();
			chunkInstance.append(responceText.getBytes(), 0, responceText
					.getBytes().length);

			OutputBuffer buffer = response.getOutputBuffer();
			buffer.doWrite(chunkInstance, response);

			response.finish();
		}

	}

	/**
	 * Grizzly recycling
	 */
	public void afterService(Request request, Response response)
			throws Exception {
		request.recycle();
		response.recycle();
	}

	public void fireAdapterEvent(String string, Object object) {
	}

	// ------------------------- / Grizzly -----------------------------

}